using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Media;
using Common;
using ImageProcessing.Common;
using ImageProcessing.Detectors;
using ImageProcessing.Engine;
using ImageProcessing.PointsSampler;
using ImageProcessing.Storage;
using NUnit.Framework;

namespace ImageProcessing.Tests.Engine
{
    public abstract class ImageProcessingEngineTestBase
    {
        private int _imageCount;
        private ImageProcessingEngine _ipe;
        private readonly ManualResetEvent _syncUIEvent = new ManualResetEvent(true);
        private readonly ManualResetEvent _finishedEvent = new ManualResetEvent(false);

        private readonly List<string> _imageTestList = new List<string>();

        protected readonly List<TestCaseData> TestCaseData = new List<TestCaseData>();

        private TagInfo _tagInfo = new TagInfo(Guid.NewGuid(), "Object");

        private int _foundCount;

        private int _height;
        private int _width;

        [SetUp]
        public void Setup()
        {
            _imageTestList.Clear();
            _finishedEvent.Reset();
            _imageCount = 0;
            _foundCount = 0;
        }

        [TearDown]
        public void TearDown()
        {
            _ipe.Dispose();
            _ipe.LearnComplete -= LearnComplete;
            _ipe.DescriptorsUpdate -= DescriptorsUpdate;
            _ipe = null;
        }

        protected void BaseTester(CameraMode cameraMode, DetectorType detectorType, InterestPointsSamplerFactory.SampleType sampleType, string learnFileName, IEnumerable<string> compareFileNames)
        {
            _imageTestList.AddRange(compareFileNames);

            byte[] rawImage;

            if (learnFileName.Contains("raw"))
            {
                OnlineImageArchiver onlineImageArchiver = new OnlineImageArchiver();
                LoadedImage loadedImage = onlineImageArchiver.LoadRawImage(learnFileName);
                rawImage = loadedImage.rawImage;
            }
            else
            {
                var wb = HelperMethods.LoadOrigSizeImage(learnFileName, PixelFormats.Gray8);
                rawImage = HelperMethods.LoadYImage(learnFileName, wb.PixelWidth, wb.PixelHeight).rawImage;
                _width = wb.PixelWidth;
                _height = wb.PixelHeight;
            }

            _ipe = new ImageProcessingEngine(_width, _height, GetNextImageARGB, GetNextRawImage, _syncUIEvent, cameraMode,
                                            detectorType);
            _ipe.LearnComplete += LearnComplete;
            _ipe.DescriptorsUpdate += DescriptorsUpdate;

            _ipe.SampleType = sampleType;

            _ipe.ManualLearnImage(rawImage, _tagInfo);

            _ipe.Start();

            _finishedEvent.WaitOne();

            Assert.AreEqual(_imageCount, _foundCount);
        }

        private void GetNextImageARGB(int[] argb)
        {
            var argbLoaded = HelperMethods.LoadARGBImage(_imageTestList[_imageCount], PixelFormats.Pbgra32, _width, _height);

            Array.Copy(argbLoaded, argb, argb.Length);

            _imageCount++;
        }

        private void GetNextRawImage(byte[] greyScale)
        {
            OnlineImageArchiver onlineImageArchiver = new OnlineImageArchiver();
            LoadedImage loadedImage = onlineImageArchiver.LoadRawImage(_imageTestList[_imageCount]);
            var rawImage = loadedImage.rawImage;

            Array.Copy(rawImage, greyScale, greyScale.Length);

            _imageCount++;
        }


        private void DescriptorsUpdate(ImageScanResultsDTO imageScanResultsDTO)
        {
            if (imageScanResultsDTO.ObjectFound)
                _foundCount++;

            if (_imageCount == _imageTestList.Count)
            {
                _ipe.Dispose();
                _finishedEvent.Set();
            }

            _syncUIEvent.Set();
        }

        private void LearnComplete()
        {
            _ipe.SaveLearnt(_tagInfo);
        }
    }
}